import Vue from "vue";
import BaseModel from "../models/BaseModel.js";
import ListModel from "../models/ListModel.js";
import Util from "./util.js";
// import Services from "./services";
import LoaderProxy from "./loaderProxy";
import request from "@/utils/request";
import qs from "qs";
import { mountManualTriggerGuide, loadAutoTriggerGuide } from "@/utils/guide";

let loaders = Symbol("loaders");

class Controller {
  //#region 构造函数
  constructor() {
    this[loaders] = [];
    this.reload = true;
    this.vm = {};
    /**
     * 打开页面时需要请求的接口地址，有query和model两种，对应类型如下：
      this.urls = {
       query: ['/api', '/api2', '/api3'],               // 类型： list  list$1  list$2
       model: ['/modelApi', '/modelApi2', '/modelApi3'] // 类型： form  form$1  form$2
      }
     */
    this.urls = {};
    /**
     * 按钮的权限标识，示例：
      this.permissions = {
        add: 'system:user:add',       // 新增
        view: 'system:user:view',     // 查看
        edit: 'system:user:edit',     // 编辑
        delete: 'system:user:delete'  // 删除
      };
      关于列表页的权限，如果你能访问到这个页面，那可以查看列表数据，不然不要赋予列表页的权限。
      该变量只控制框架提供的新增、查看、编辑、删除按钮的权限，其他按钮的权限需自行控制
     */
    this.permissions = {};
    this.context = {};
    this.res = {
      deleteConfirm: "确定要删除选择的记录吗？",
      deleteError: "删除失败！",
      deleteSuccess: "删除成功！",
      noSelectAtDeleting: "请先选择要删除的记录。",
      createError: "创建失败！",
      createSuccess: "创建成功！",
      updateError: "更新失败！",
      updateSuccess: "更新成功！"
    };
    this.listOptions = {
      searchKey: "allInLike"
    };
    this.autoMountManualTriggerGuide = false;
  }
  //#endregion

  //#region 属性
  get $el() {
    return this.vm.$el;
  }

  get $framework() {
    return Vue.prototype.$framework;
  }

  get $data() {
    return this.context;
  }

  get $util() {
    return Util;
  }

  get $params() {
    let q = this.vm.$route.query;
    let ps = this.vm.$route.params;
    let attrs = this.vm.$attrs;
    //如果是模态窗口，不取值当前路由参数
    if (!this.$util.isEmpty(attrs) && attrs._modal) {
      if (Object.keys(attrs).length > 1) {
        return this.$util.extend({}, attrs);
      }
    } else {
      if (
        !this.$util.isEmpty(q) ||
        !this.$util.isEmpty(ps) ||
        !this.$util.isEmpty(attrs)
      ) {
        return this.$util.extend({}, q || {}, ps || {}, attrs || {});
      }
    }

    let queryString = qs.parse(window.location.search, {
      ignoreQueryPrefix: true
    });
    if (!this.$util.isEmpty(queryString)) {
      return queryString;
    }
    return {};
  }

  get $formatter() {
    return this.$framework.formatter;
  }
  //#endregion

  //#region 禁止重写方法
  polyfill() {
    this.onInit();
    // Services.setInstance("controller", this.vm.$route.path, this);
  }
  //#endregion

  //#region 初始化
  onBeforeInit() {
    this.buildContext();
  }
  onInit() {
    //overwrite
  }
  buildContext() {
    let models = new BaseModel();
    if (this.urls.query) {
      Util.each(Util.buildArray(this.urls.query), (t, i) => {
        models = Util.extend(models, new ListModel(i));
      });
    }
    if (this.mixin().data) {
      Util.extend(models, this.mixin().data());
    }
    this.context = models;
    this.context.pageLoading = false;
    this.onBuildContext(models);
  }
  onBuildContext(models) {
    //overwrite
  }
  //#endregion

  //#region 加载数据，需要返回Promise，Promise的then方法会返回一个新的Promise实例
  getViewModel(conditions, preloader = false) {
    this.context.pageLoading = true;
    let loading;
    if (preloader) {
      loading = this.vm.appLoading("数据加载中...");
    }

    return new Promise((resolve, reject) => {
      new LoaderProxy(this, conditions).load(resolve, reject, preloader);
    })
      .then(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      })
      .catch(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      });
  }

  onBeforeQuery(type, conditions, params) {}

  /**
   * 调整数据
   *
   * 后台返回的viewModel里有search属性，而且可能search为空，导致把页面上的this.search的内容覆盖了
   * 所以该方法主要是调整类似该情况的响应数据，一般不用重写，如有需要可重写
   * @param {*} type 类型，model请求取值form, form$1, form$2 ... query请求取值list, list$1, list$2 ...
   * @param {*} isSuccess 请求是否成功
   * @param {*} result 该请求返回的数据
   */
  adaptData(type, isSuccess, result) {
    if (
      type.indexOf("form") != -1 &&
      result &&
      result.search &&
      this.$util.isEmpty(result.search)
    ) {
      delete result.search;
    }
    return result;
  }
  onAfterQuery(type, isSuccess, result) {
    return result;
  }
  onConvertItem(type, item) {}

  //#endregion

  //#region 数据绑定
  bind(data) {
    if (Util.isArray(data)) {
      Util.each(data, t => {
        Util.extend(this.context, t);
      });
    } else {
      Util.extend(this.context, data);
    }

    this.onBinded(data, this.context);
  }
  onBinded(data, context) {}
  //#endregion

  //#region 列表
  getLoader(type = "list") {
    return this[loaders][type];
  }
  setLoader(loader) {
    this[loaders][loader.getType()] = loader;
  }
  refresh(type, done) {
    this.getLoader(type)
      .refresh()
      .then(ret => {
        if (ret === false) {
          return;
        }
        if (Util.isFunction(done)) {
          done();
        }
      });
  }
  infinite(type) {
    this.getLoader(type).infinite();
  }
  //#endregion

  //#region 搜索
  //(查询条件，类型)，类型：表单form，列表list\list$1\list$2
  searchQuery(value, type) {
    if (Util.isString(value)) {
      this.setSearch(this.listOptions.searchKey, value, type);
    } else {
      if (value instanceof MouseEvent) {
        value = {};
      }
      value = value || {};
      if (!this.$util.isEmpty(value)) {
        value = {
          query: value
        };
      }
    }
    let $table = this.vm.$refs["qmTable"];
    if ($table) {
      $table.tableLoading = true;
    }
    this.getLoader(type)
      .query(Util.isString(value) ? {} : value)
      .then(
        values => {
          this.bind(values);
          if ($table) {
            $table.clearSort();
            $table.tableLoading = false;
          }
        },
        values => {
          if ($table) {
            $table.tableLoading = false;
          }
          this.vm.msgError("请求失败，请稍候再试");
          console.error(values);
        }
      );
  }

  /**
   * 使用指定type的loader请求数据
   * @param {*} params 参数，需指定key和value
   * @param {*} type loader的类型
   */
  fetchData(params, type, preloader = true) {
    let loading;
    if (preloader) {
      loading = this.vm.appLoading("数据加载中...");
    }
    return new Promise((rs, rj) => {
      this.getLoader(type)
        .query(params)
        .then(
          values => {
            this.bind(values);
            if (preloader) {
              loading.close();
            }
            rs();
          },
          values => {
            if (preloader) {
              loading.close();
            }
            this.vm.msgError("请求失败，请稍候再试");
            console.error(values);
            rs();
          }
        );
    });
  }

  /**
   * 设置查询条件，仅适用于列表请求
   * @param {*} key 参数名
   * @param {*} value 参数值
   * @param {*} type 列表类型，list, list$1, list$2 等
   */
  setSearch(key, value, type) {
    var sKey = "search";
    if (type) {
      sKey += type.replace("list", "");
    }
    if (this.context[sKey] == undefined) {
      this.context[sKey] = {};
    }
    var inst = this.context[sKey];
    if (Util.isString(value)) {
      value = Util.toString(value);
    }
    inst[key] = value;
  }
  /**
   * 设置查询条件，当该名称的参数不存在时才有效，仅适用于列表请求
   * @param {*} key 参数名
   * @param {*} value 参数值
   * @param {*} type 列表类型，list, list$1, list$2 等
   */
  setSearchIfNull(key, value, type) {
    var sKey = "search";
    if (type) {
      sKey += type.replace("list", "");
    }
    if (this.context[sKey] == undefined) {
      this.setSearch(key, value, type);
    } else {
      var inst = this.context[sKey];
      if (inst[key] == undefined) {
        this.setSearch(key, value, type);
      }
    }
  }
  /**
   * 获取列表请求的请求参数值
   * @param {*} key 参数名
   * @param {*} type 列表类型，list, list$1, list$2 等
   */
  getSearch(key, type) {
    let sKey = "search";
    if (type) {
      sKey += type.replace("list", "");
    }
    if (this.context[sKey]) {
      return this.context[sKey][key];
    }
    return "";
  }
  /**
   * 设置请求参数，适用于表单请求和列表请求
   * @param {*} key 参数名
   * @param {*} value 参数值
   * @param {*} type 类型，form, form$1, form$2, list, list$1, list$2 等
   */
  setRequestParam(key, value, type = "list") {
    var sKey = "initParams_";
    if (type) {
      sKey += type;
    }
    if (!this.context[sKey]) {
      this.context[sKey] = {};
    }
    var inst = this.context[sKey];
    if (Util.isString(value)) {
      value = Util.toString(value);
    }
    inst[key] = value;
  }
  /**
   * 获取请求参数
   * @param {*} key 参数名
   * @param {*} type 类型，form, form$1, form$2, list, list$1, list$2 等
   */
  getRequestParam(key, type) {
    let sKey = "initParams_";
    if (type) {
      sKey += type;
    }
    if (this.context[sKey]) {
      return this.context[sKey][key];
    }
    return "";
  }
  //#endregion

  /**
   * 获取实体数据，如果参数没有指定实体的主键属性和值，则返回一个空的实体
   * @param {*} params 参数
   * @param {*} url 请求的url
   */
  getEntity(
    params = {
      pageAction: "create"
    },
    url = this.urls.entity
  ) {
    return new Promise((resolve, reject) => {
      if (!url) {
        this.vm.msgError("没有指定获取实体的url");
        reject("没有指定获取实体的url");
      }

      this.onBeforeGetEntity(params);
      request({
        url: url,
        method: "post",
        data: params
      })
        .then(r => {
          this.onAfterGetEntity(r);
          if (r && !r.initMessage) {
            resolve(r);
          } else {
            reject(r.initMessage || "请求数据失败");
          }
        })
        .catch(e => {
          reject(e);
        });
    });
  }

  onBeforeGetEntity(params) {}

  onAfterGetEntity(result) {}

  //#region 保存
  onBeforeSave(postModel) {
    return true;
  }

  // 表单校验方法，如果使用qm-table组件的表单功能，则不需重写此方法
  onValidate() {
    return Promise.resolve();
  }

  save(postModel = this.context.models, url) {
    return new Promise((resolve, reject) => {
      if (!url) {
        url = this.appendPrimaryKey(this.urls.save);
      }
      if (postModel == undefined || url == undefined) {
        this.afterSave(false, {
          message: "PostModel或者URL不可为undefined"
        });
        reject();
      } else {
        postModel = Util.cloneDeep(postModel);
        postModel.pageAction = this.context.pageAction;
        this.onValidate()
          .then(valid => {
            let next = this.onBeforeSave(postModel);
            // undefined 是没有写return返回值的情况，可能有人忘记写，这里帮忙处理了
            if (next === true || next === undefined) {
              request({
                url: url,
                method: "post",
                data: postModel
              })
                .then(r => {
                  this.afterSave(r.success, r);
                  resolve(r);
                })
                .catch(e => {
                  this.afterSave(false, e);
                  reject(e);
                });
            } else {
              reject();
            }
          })
          .catch(e => {
            this.vm.notifyError("表单校验不通过！");
            reject();
          });
      }
    });
  }
  afterSave(isSuccess, result) {
    if (
      isSuccess &&
      result.parameters &&
      result.parameters.keys &&
      this.context.pageAction == "create"
    ) {
      this.context.pageAction = "edit";
      this.context.pageActionText = "编辑";
      this.context.primaryKey = result.parameters.keys;
    }

    this.vm.$message({
      showClose: true,
      message:
        result.message || (isSuccess ? "保存成功" : "保存失败，请稍后重试"),
      type: isSuccess ? "success" : "error",
      onClose: $message => {
        this.onAfterSave(isSuccess, result);
      }
    });
  }
  onAfterSave(isSuccess, result) {}
  //#endregion

  //#region 删除
  onBeforeRemove(postModel) {
    return true;
  }
  onAfterRemove(isSuccess, result) {}

  afterRemove(isSuccess, result) {
    this.vm.$message({
      showClose: true,
      message:
        result.message ||
        (isSuccess ? this.res.deleteSuccess : this.res.deleteError),
      type: isSuccess ? "success" : "error",
      onClose: $message => {
        this.onAfterRemove(isSuccess, result);
      }
    });
  }
  remove(
    postModel = this.context.primaryKey,
    url = this.urls.delete || this.urls.remove
  ) {
    return new Promise((resolve, reject) => {
      if (postModel == undefined || url == undefined) {
        this.afterRemove(false, {
          message: "PostModel或者URL不可为undefined"
        });
        reject();
      } else {
        if (this.onBeforeRemove(postModel)) {
          this.vm
            .$confirm("确定删除嘛？", "提示", {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning"
            })
            .then(() => {
              let loading = this.vm.appLoading("正在删除...");
              postModel = Util.isArray(postModel) ? postModel : [postModel];

              request({
                url: url,
                method: "post",
                data: {
                  delete: JSON.stringify(postModel)
                }
              })
                .then(r => {
                  this.afterRemove(r.success, r);
                  loading.close();
                  resolve(r);
                })
                .catch(e => {
                  this.afterRemove(false, e);
                  loading.close();
                  reject(e);
                });
            })
            .catch(() => {
              reject();
            });
        }
      }
    });
  }
  //#endregion

  appendPrimaryKey(url) {
    if (!url) {
      return undefined;
    } else {
      let primaryKey = this.context.primaryKey || {};
      for (let o in primaryKey) {
        let v = primaryKey[o];
        if (v != undefined) {
          let joinChar = url.indexOf("?") == -1 ? "?" : "&";
          url += joinChar;
          url += o + "=" + (primaryKey[o] || "");
        }
      }
      return url;
    }
  }

  // 该配置目前无效
  disableCache() {
    return true;
  }

  // 是否显示进入页面时的加载中图标
  showLoading() {
    return true;
  }

  // 是否自动触发加载完成事件
  autoLoadDone() {
    return true;
  }

  //#region vue
  mixin() {
    return {};
  }
  //#endregion

  //#region 静态方法，vue-loader加载vue页面时都会调用default方法
  static get default() {
    return this.export({});
  }

  // 给 qm-vue-loader 用
  static get isQmController() {
    return true;
  }

  static export(options) {
    // let instance = Services.getInstance(this);
    // instance.onBeforeInit();
    // if (!instance.context || Util.isEmpty(instance.context)) {
    //   instance.buildContext();
    // }
    // let mixin = instance.mixin();
    // Util.extend(options, mixin);
    // if (instance.mixins) {
    //   Util.extend(options, instance.mixins);
    // }
    let instance = this;
    Util.extend(options, instance.prototype.mixin());

    options.data = function() {
      return this.super.context;
    };
    options.provide = function() {
      let mixin = this.super.mixin();
      let provide =
        mixin.provide && Util.isFunction(mixin.provide)
          ? mixin.provide()
          : mixin.provide;
      return Util.extend(
        {},
        {
          pageVue: this
        },
        provide || {}
      );
    };
    options.beforeRouteEnter = function(to, from, next) {
      next();
    };
    options.beforeRouteUpdate = function(to, from, next) {
      next();
    };

    options.beforeCreate = function() {
      let ins = new instance.prototype.constructor();
      ins.onBeforeInit();
      if (!ins.context || Util.isEmpty(ins.context)) {
        ins.buildContext();
      }
      let mixin = ins.mixin();
      Util.extend(options, mixin);
      if (ins.mixins) {
        Util.extend(options, ins.mixins);
      }

      ins.vm = this;
      this.super = ins;
      if (mixin.beforeCreate) {
        mixin.beforeCreate.apply(ins.vm);
      }
    };
    options.activated = function() {
      let mixin = this.super.mixin();
      if (mixin.activated) {
        mixin.activated.apply(this.super.vm);
      }
      if (
        this.autoMountManualTriggerGuide ||
        this.super.autoMountManualTriggerGuide
      ) {
        mountManualTriggerGuide(this.$route.path);
      }
    };
    options.created = function() {
      this.super.polyfill();
      let loading = this.super.showLoading();
      if ((this.$attrs || {}).showAppLoading === false) {
        loading = false;
      }
      let mixin = this.super.mixin();
      this.super.getViewModel({}, loading).then(() => {
        if (mixin.created) {
          mixin.created.apply(this.super.vm);
        }
        if (this.super.autoLoadDone()) {
          if (this.pageLoadDone) {
            this.pageLoadDone();
          } else {
            this.$emit("loaded");
          }
        }
      });
    };
    options.beforeMount = function() {
      let mixin = this.super.mixin();
      if (mixin.beforeMount) {
        mixin.beforeMount.apply(this.super.vm);
      }
    };
    options.mounted = function() {
      let mixin = this.super.mixin();
      if (mixin.mounted) {
        mixin.mounted.apply(this.super.vm);
      }
      loadAutoTriggerGuide(this.$route.path);
    };
    options.methods = Util.extend(
      {},
      {
        pageLoadDone() {
          this.$emit("loaded");
        },
        getViewModel(conditions) {
          return this.super.getViewModel(conditions);
        },
        getEntity(params, url) {
          return this.super.getEntity(params, url);
        },
        save(postModel, url) {
          if (postModel instanceof MouseEvent) {
            postModel = this.models;
          }
          return this.super.save(postModel, url);
        },
        remove(postModel, url) {
          return this.super.remove(postModel || this.primaryKey, url);
        },
        refresh(type, done) {
          this.super.refresh(type, done);
        },
        infinite(type) {
          this.super.infinite(type);
        },
        searchQuery(query, type) {
          this.super.searchQuery(query, type);
        },
        fetchData(params, type = "list", preloader) {
          return this.super.fetchData(params, type, preloader);
        },
        onSearch: function(query) {
          this.super.searchQuery(query);
        },
        onReset: function() {
          this.super.searchQuery("");
        },
        resetSearch(formName = "searchForm") {
          let $form = this.$refs[formName];
          if ($form) {
            $form.resetFields();
          }
        },
        setSearch(key, value, type) {
          this.super.setSearch(key, value, type);
        },
        setSearchIfNull(key, value, type) {
          this.super.setSearchIfNull(key, value, type);
        },
        isListEmpty(type) {
          try {
            let key = "query";
            if (type) {
              key += type.replace("list", "");
            }
            return (
              !this.super.context[key] ||
              !this.super.context[key].data ||
              this.super.context[key].data.length == 0
            );
          } catch (e) {
            console.error(e);
          }
          return false;
        },
        getPermission(key) {
          return this.super.permissions[key] || "";
        },
        // 配合代码生成器来用，create和qmGenForm这两个ref值都是代码生成器生成的，如不同请自行修改
        defaultFormValidate(forms) {
          return this.$refs["create"].$refs["qmGenForm"].validate();
        },
        // 获取工作流的相关参数
        getWorkflowArgs(params) {
          return new Promise((rs, rj) => {
            let loading = this.notifyInfo("获取数据中...");
            request({
              url: "/workflow/getWorkflowArgs",
              method: "post",
              data: params
            })
              .then(rlt => {
                loading.close();
                rs(rlt);
              })
              .catch(rlt => {
                this.notifyError("获取数据失败，请稍后再试！");
                rj(rlt);
              });
          });
        }
      },
      options.methods
    );
    return options;
  }
  //#endregion
}
export default Controller;
